/*
 *	$Id: emobj.h 121 2009-06-10 23:14:02Z wabsie $
 */

#ifndef _EMOBJ_H
#define	_EMOBJ_H

#include <cstdlib>		// EXIT_FAILURE
#include <cstdio>		// printf
#include <cassert>		// STLs assert
#include "matematik.h"	// matematik

using namespace std;

class emobj;			// Prototyper...
class Medium;			// (fortæl compiler at deklarationerne er længere nede)

const skalar epsilon0 = 8.8541878176e-12;	// Vakuum permittivitet
const skalar mu0 = pi*4e-7;             	// Vakuum permeabilitet


class Field
{
public:
	Field(const emobj* EMobject, fieldPoint::felttype _type);

	virtual fieldPoint calc(coord<3> punkt) = 0;

	const skalar& mu;		// Referance til materialets mu
	const skalar& epsilon;	// ...
	const vektor<3>& nul_potentiale;	// Referance potentialet

	const skalar& styrke;	// Referance til emobjektets styrke
	const vektor<3>& off;	// ...
	const vektor<3>& ret;
	const vektor<3>& v;

	const fieldPoint::felttype type;

	enum pripot {primary = 0, potential = 1};
};


class emobj
{
public:
	emobj(Medium *m, skalar _styrke, vektor<3> offset, vektor<3> v_orient);

	void setOrient(const vektor<3>& v_orient);
	vektor<3> getOrient() const;
	virtual string getInfo(const char* fmt = "%.2fE%02.0f");

	Medium* material;
	Field* felt[2];	// Primær- (E eller B) og potentialefeltet (V eller A)

	skalar styrke;  // Styrken (en af rho_l, I, Q ...)
	vektor<3> off;  // Translation
	vektor<3> ret;	// Orientering/retning (ignoreres ved punktladning)
	vektor<3> v;   // Normeret udgave af retningsvektoren

	enum type {pcharge = 0, lcharge = 1, lcurrent = 2, unknown = 3};
	type mintype;
	static const char *strType[];
};


class pointcharge : public emobj
{
public:
	using emobj::styrke;	// Bring arvede variable ind i scope
	using emobj::off;		// ...
	using emobj::ret;
	using emobj::v;

	// v_orient ignoreres for punktladningen, men inkluderes grundet konformitet
	pointcharge(Medium *m, skalar Q, vektor<3> offset, vektor<3> v_orient);

	// Specielt for punktladning: Override arvet getInfo()
	string getInfo(const char* fmt = "%.2fE%02.0f");

	class Efield : public Field
	{
	public:
		Efield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};

	class Vfield : public Field
	{
	public:
		Vfield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};
};


class linecharge : public emobj
{
public:
	using emobj::styrke;
	using emobj::off;
	using emobj::ret;
	using emobj::v;

	linecharge(Medium *m, skalar _rho_l, vektor<3> offset, vektor<3> v_orient);

	class Efield : public Field
	{
	public:
		Efield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};

	class Vfield : public Field
	{
	public:
		Vfield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};
};


class linecurrent : public emobj
{
public:
	using emobj::styrke;
	using emobj::off;
	using emobj::ret;
	using emobj::v;

	linecurrent(Medium *m, skalar _I, vektor<3> offset, vektor<3> v_orient);

	class Bfield : public Field
	{
	public:
		Bfield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};

	class Afield : public Field
	{
	public:
		Afield(const emobj* EMobject);
		fieldPoint calc(coord<3> R);
	};
};


class Medium :
	public vector<emobj*>	// Et Medium er blot et array af
{							// pointere til emobjekter + lidt mere
	/*
	 * Et medium indeholder EM-objekter
	 */

public:
	Medium();					// Default til free space

	void addObj(emobj::type objtype, skalar styrke, vektor<3> offset, vektor<3> v_orient);
	void setMediumRelative(skalar epsilon_r, skalar mu_r);

	skalar epsilon;				// Absolut permittivitet
	skalar mu;					// Absolut permeabilitet
	vektor<3> nul_potentiale;	// Referance potentialet

	Field::pripot mainField;	// Det felt vis intensitet vises som baggrund
};


#endif	/* _EMOBJ_H */

